# 功能模块：产线级，主页面入口
# 作者：dl
# 描述：产线级业务逻辑入口

import os
import platform
import vtk
from trame.app import asynchronous
import datetime
import asyncio
# from gltf.Loader import GLTFLoader
# from gltf.Renderer import GLTFRenderer
from gltf import GLTFLoader, GLTFRenderEngine

from visualizationCom.tools.color import hex_to_rgba
from visualizationCom.tools.utils import getGltfPath
from visualizationCom.bussiness.productlineFunction.productlineDataFunction import getDeviceInfo,getDeviceList

class productlineScene:
    # 构造函数
    def __init__(self, parent, webState, webCtrl):

        self.parent = parent
        self.webState = webState
        self.webCtrl = webCtrl

        self.hasLoadScene = False  # 用于判断是否存在缓存
        # self.renderer = GLTFRenderer()

        self.engine = GLTFRenderEngine()
        self.renderer = self.engine.GetDefaultRenderer()    
        self.renderer.SetGround(1, scale=5)
        self.camera = self.engine.GetCamera()

        bg_color = hex_to_rgba('#132c4a')
        self.renderer.SetBackground(bg_color[0], bg_color[1], bg_color[2])

        self.materialColorList = []  # 记录模型各个零部件材质原来的颜色

        # 定义相机初始化位置，用于重置
        self.initial_position = 0
        self.initial_focal_point = 0
        self.initial_view_up = 0

        self.light = vtk.vtkLight()

        self.animationLastDateTime = None  # 动画需要用到的时间

    def enterScene(self):

        # 异步渲染
        asyncio.run(self.startLoading())
        self.parent.mouseInteractorEvent.outline.Clear()
        self.parent.mouseInteractorEvent.lastPick = None

        self.renderer.SetActiveCamera(self.camera)
        with self.webState:
            self.webState.sceneKey = 'productline'
            self.webState.showProductlineScene = True
            self.webState.showWorkshopScene = False
            self.webState.showFactoryScene = False
            self.webState.showProductScene = False
            self.webState.showDeviceScene = False
        
        self.parent.currentRenderer = self.renderer

        # getDeviceList(self.webState)

        # 读取模型路径
        file_names_glb = getGltfPath()

        file_name_initial = file_names_glb[0]

        # 暂时写死模型
        if self.hasLoadScene == False:
            # camera = self.renderer.GetActiveCamera()
            camera = self.camera
            self.initial_position = camera.GetPosition()
            self.initial_focal_point = camera.GetFocalPoint()
            self.initial_view_up = camera.GetViewUp()

            self.load_file_loader(file_name_initial)

        fileNum = len(file_names_glb)
        modelList = []
        if fileNum > 0:
            for file_name in file_names_glb:
                if platform.system() == "Windows":
                    file_name = file_name.replace("\\", "/")

                modelList.append({"name": os.path.basename(
                    file_name), "style": {}, "file_name": file_name})

            modelList[0]["style"] = {"border": "1px solid red"}

        self.getModelInfo()

        self.hasLoadScene = True

        self.parent.renderWindow.AddRenderer(self.renderer)
        self.parent.renderWindow.RemoveRenderer(self.parent.workshop.renderer)
        self.parent.renderWindow.RemoveRenderer(self.parent.product.renderer)

        # 重置交互器
        self.engine.SetRenderWindow(self.parent.renderWindow)
        self.parent.mouseInteractorEvent.SetDefaultRenderer(self.renderer)
        self.parent.mouseInteractorEvent.SetOutlineRenderer(self.engine.GetOutlineRenderer())

        # self.parent.mouseInteractorEvent.outline.Clear()
        # self.parent.mouseInteractorEvent.lastPick = None
        self.parent.mouseInteractorEvent.selectActorIndex = -1

        with self.webState:
            self.webState.modelList = modelList
            self.webState.loadingFlag = False

    def load_file_loader(self, file_name):

        if platform.system() == "Windows":
            file_name = file_name.replace("\\", "/")

        self.renderer.RemoveAllViewProps()

        self.webState.deviceHealthDegreeShow = False
        self.webState.btnTitle = '模拟故障'

        self.reader = GLTFLoader()
        self.reader.Load(file_name)
        self.renderer.AddScene(self.reader.GetScene())

        self.reader_detail_two = GLTFLoader()
        self.reader_detail_two.Load(file_name)
        scene_two = self.reader_detail_two.GetScene()
        scene_two.transform.Translate(1, 0, 0)
        self.renderer.AddScene(scene_two)

        self.reader_detail_three = GLTFLoader()
        self.reader_detail_three.Load(file_name)
        scene_three = self.reader_detail_two.GetScene()
        scene_three.transform.Translate(-1, 0, 0)
        self.renderer.AddScene(scene_three)

        # 记录颜色的数组用二维数组
        self.materialColorList = [[]]

        # 石老师的引擎修改后，颜色标的需要跟着修改
        # for assembly in self.reader.meshes:
        #     for actor in assembly.GetParts():
        #         color = actor.GetProperty().GetColor()
        #         self.materialColorList[0].append(color)

        tempAnimationList = []
        if len(self.reader.animations):
            # 解构，否则页面不会更新动画列表
            for index in range(len(self.reader.animations)):
                tempAnimationList.append(index)

            with self.webState:
                self.webState.animationFlag = True
                self.webState.animation_index = 0  # 默认播放第一个动画

                self.webState.showAnimationSelect = True  # 将动画列表显示
                self.webState.animationList = tempAnimationList
        else:
            with self.webState:
                self.webState.animationFlag = False
                self.webState.showAnimationSelect = False

    def getModelInfo(self):
        actor_collection = self.renderer.GetActors()
        total_points = 0
        total_lines = 0
        total_cells = 0

        for i in range(actor_collection.GetNumberOfItems()):
            actor = actor_collection.GetItemAsObject(i)
            total_points += actor.GetMapper().GetInput().GetNumberOfPoints()
            data = actor.GetMapper().GetInput()
            for i in range(data.GetNumberOfCells()):
                cell = data.GetCell(i)
                cellType = cell.GetCellType()
                if cellType == vtk.VTK_LINE or cellType == vtk.VTK_POLY_LINE:
                    total_lines += 1
                if cellType in [vtk.VTK_TRIANGLE, vtk.VTK_QUAD, vtk.VTK_POLYGON]:
                    total_cells += 1

        with self.webState:
            self.webState.total_points = total_points
            self.webState.total_lines = total_lines
            self.webState.total_cells = total_cells

    def restCamera(self):
        # 获取当前相机
        camera = self.renderer.GetActiveCamera()

        # 重置相机的位置和方向为初始状态
        camera.SetPosition(self.initial_position)
        camera.SetFocalPoint(self.initial_focal_point)
        camera.SetViewUp(self.initial_view_up)
        self.renderer.ResetCamera()

    @asynchronous.task
    async def async_animation(self):
        while (self.webState.animationFlag and self.reader.animations):
            now = datetime.datetime.now()
            if self.animationLastDateTime is None:
                self.animationLastDateTime = now
                self.renderer.ResetCameraClippingRange()
            elapsed = (now - self.animationLastDateTime).total_seconds() * \
                self.webState.animationSpeed

            if elapsed > self.reader.animations[self.webState.animation_index].GetEndTime():
                self.animationLastDateTime = now
                elapsed = 0

            self.reader.animations[self.webState.animation_index].SetAnimationTime(
                elapsed)

            await asyncio.sleep(0.05)
            self.webCtrl.view_update()

        # 注销异步程序
        if self.webState.animationFlag == False:
            print('线程退出')
            return

    def setDeviceError(self):
        # 获取设备运行状态信息
        getDeviceInfo(self.webState)
        self.add3DText()

        # temp = self.reader
        # for assembly in temp.meshes:
        #     for actor in assembly.GetParts():
        #             actor.GetProperty().SetColor(1.0, 0.0, 0.0)


        self.initCircle()

        self.parent.renderWindow.Render()
        self.cancelDeviceStatusAnimation = False  # 注销异步线程的标志
        self.updateDeviceStatusAnimation()
        self.webCtrl.view_update()

    def resetDeviceError(self):

        # temp = self.reader
        # k = 0
        # for assembly in temp.meshes:
        #     for actor in assembly.GetParts():
        #             actor.GetProperty().SetColor(
        #                 self.materialColorList[0][k])

        self.renderer.RemoveActor(self.image_actor)
        self.renderer.RemoveActor(self.textActor)
        self.renderer.RemoveActor(self.imageActor_dialogbox)
        self.cancelDeviceStatusAnimation = True  # 注销异步线程的标志
        self.webCtrl.view_update()

    def initCircle(self):
        # 加入光圈
        # 加载图像数据
        CURRENT_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))

        user_input = "images/"

        # 结合 CURRENT_DIRECTORY 和 user_input 形成新的地址
        new_directory = os.path.join(CURRENT_DIRECTORY, user_input)

        reader = vtk.vtkPNGReader()
        reader.SetFileName(new_directory+"circle.png")
        reader.Update()

        # 获取图片数据信息
        bounds = reader.GetOutput().GetBounds()
        # 计算变换矩阵
        self.center = [(bounds[0] + bounds[1]) / 2, (bounds[2] +
                                                     bounds[3]) / 2, (bounds[4] + bounds[5]) / 2]

        # 设置初始缩放比例和原点位置
        self.init_scale = 0.005
        self.init_origin = [bounds[0], bounds[2], bounds[4]]

        # 设置最终缩放比例
        self.final_scale = 0.015

        # 创建图片Actor
        self.image_actor = vtk.vtkImageActor()
        self.image_actor.SetInputData(reader.GetOutput())
        self.image_actor.SetScale(
            self.init_scale, self.init_scale, self.init_scale)

        self.offset_x = 0.5
        self.offset_y = -0.5
        self.offset_z = 0.15
        self.image_actor.SetPosition(
            self.offset_x, self.offset_y, self.offset_z)

        # # 对图像演员进行旋转
        transform = vtk.vtkTransform()
        transform.RotateWXYZ(90, 1, 0, 0)
        self.image_actor.SetUserMatrix(transform.GetMatrix())

        self.renderer.AddActor(self.image_actor)

    def add3DText(self):
        self.textActor = vtk.vtkTextActor3D()
        self.textActor.SetInput("设备故障")  # 设置中文文字 换行格式 设备故障\n2023-12-26

        # 使用FreeType字体库和字符纹理映射
        textProperty = self.textActor.GetTextProperty()
        textProperty.SetFontFamily(vtk.VTK_FONT_FILE)  # 设置字体为FreeType字体库

        # 设置中文字体文件路径
        CURRENT_DIRECTORY = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))

        user_input = "font/"

        # 结合 CURRENT_DIRECTORY 和 user_input 形成新的地址
        new_directory = os.path.join(CURRENT_DIRECTORY, user_input)
        textProperty.SetFontFile(
            new_directory + "sanjizihaisonggbk.ttf")

        self.textActor.GetTextProperty().SetColor(1, 0, 0)  # 设置文字颜色为白色
        self.textActor.GetTextProperty().SetFontSize(18)  # 设置文字大小
        self.textActor.SetScale(0.005)
        self.textActor.SetPosition(0.75, 1.3, 0.01)

        # 读入图像数据
        user_input = "images/"

        # 结合 CURRENT_DIRECTORY 和 user_input 形成新的地址
        new_directory = os.path.join(CURRENT_DIRECTORY, user_input)
        reader = vtk.vtkPNGReader()
        reader.SetFileName(new_directory + "dialogbox.png")
        reader.Update()

        # 创建图像显示对象
        self.imageActor_dialogbox = vtk.vtkImageActor()
        self.imageActor_dialogbox.SetInputData(reader.GetOutput())
        self.imageActor_dialogbox.SetPosition(0.3, 0.8, 0)
        self.imageActor_dialogbox.SetScale(0.0005)
        self.imageActor_dialogbox.SetOpacity(0.7)

        self.renderer.AddActor(self.imageActor_dialogbox)
        self.renderer.AddActor(self.textActor)
        # 创建一个包含图像和文字的组装对象
        # assembly = vtk.vtkAssembly()
        # assembly.AddPart(self.imageActor_dialogbox)
        # assembly.AddPart(self.textActor)
        # self.renderer.AddActor(assembly)

    @asynchronous.task  # retunr 则可以注销调线程
    async def updateDeviceStatusAnimation(self):
        scale = self.init_scale
        opc = 1
        while (True):
            scale = scale + 0.0005  # 每次放0.001
            if scale > self.final_scale / 4 * 3:
                opc = opc - 0.1
            self.image_actor.SetScale(scale, scale, 1)
            self.image_actor.SetPosition(self.offset_x + (self.init_scale-scale)*self.center[0], self.offset_y + (
                self.init_scale-scale)*self.center[1], self.offset_z + (self.init_scale-scale)*self.center[2])
            self.image_actor.SetOpacity(opc)
            await asyncio.sleep(0.05)
            self.webCtrl.view_update()

            if (self.final_scale < scale):
                scale = self.init_scale
                opc = 1
            print('故障动画持续进行', self.cancelDeviceStatusAnimation)
            if self.cancelDeviceStatusAnimation:
                print('退出故障动画')
                return
   
    def lightControl(self, showFlag):
        if showFlag == True:
            self.renderer.SetAutomaticLightCreation(0)
            self.renderer.RemoveAllLights()
            self.renderer.AddLight(self.light)
        else:
            self.renderer.SetAutomaticLightCreation(1)
            self.renderer.RemoveAllLights()

    async def setLoadingState(self):
        with self.webState:
            self.webState.loadingFlag = True
        await asyncio.sleep(0.05)

    async def startLoading(self):
        task = asyncio.create_task(self.setLoadingState())
        await task
